package com.czm.art_light.config;

import com.czm.art_light.constant.ArtErrorCodeEnum;
import com.czm.art_light.constant.RedisConstant;
import com.czm.art_light.entity.*;
import com.czm.art_light.exception.BusinessException;
import com.czm.art_light.mapper.*;
import com.czm.art_light.param.response.ArtArtistBasicInfoRespDto;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 布隆过滤器初始化（艺术作品ID 艺术家ID 话题ID 流派ID 类别ID）
 */
@Component
@Slf4j
public class BloomFilterInitializer implements CommandLineRunner {
    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private ArtWorkMapper artWorkMapper;

    @Autowired
    private ArtArtistMapper artArtistMapper;

    @Autowired
    private ArtMovementMapper artMovementMapper;

    @Autowired
    private ArtCategoryMapper artCategoryMapper;

    @Autowired
    private ArtTopicMapper artTopicMapper;

    // 抽象初始化方法
    private <T> RBloomFilter<T> initFilter(String key, Class<T> type) {
        RBloomFilter<T> filter = redissonClient.getBloomFilter(key);
        // 仅当过滤器不存在时初始化
        if (!filter.isExists()) {
            if (!filter.tryInit(RedisConstant.BLOOM_FILTER_EXPECTED_ELEMENTS,
                    RedisConstant.BLOOM_FILTER_ERROR_RATE)) {
                throw new BusinessException(ArtErrorCodeEnum.BLOOM_FILTER_INIT_ERROR);
            }
        }
        return filter;
    }

    @Override
    public void run(String... args) {
        // 初始化过滤器
        RBloomFilter<Integer> artworkFilter = initFilter(RedisConstant.ART_WORK_BLOOM_FILTER_KEY, Integer.class);
        RBloomFilter<Integer> artistFilter = initFilter(RedisConstant.ART_ARTIST_BLOOM_FILTER_KEY, Integer.class);
        RBloomFilter<Integer> movementFilter = initFilter(RedisConstant.ART_MOVEMENT_BLOOM_FILTER_KEY, Integer.class);
        RBloomFilter<Integer> categoryFilter = initFilter(RedisConstant.ART_CATEGORY_BLOOM_FILTER_KEY, Integer.class);
        RBloomFilter<Integer> topicFilter = initFilter(RedisConstant.ART_TOPIC_BLOOM_FILTER_KEY, Integer.class);

        // 加载数据
        loadAndAddIds(artWorkMapper::listAll, ArtWork::getId, artworkFilter, RedisConstant.BloomFilterEnum.ARTWORK.getName());
        loadAndAddIds(artArtistMapper::selectAllWithoutPage, ArtArtist::getId, artistFilter, RedisConstant.BloomFilterEnum.ARTIST.getName());
        loadAndAddIds(artMovementMapper::getAllWithoutPage, ArtMovement::getId, movementFilter, RedisConstant.BloomFilterEnum.MOVEMENT.getName());
        loadAndAddIds(artCategoryMapper::selectAllWithoutPage, ArtCategory::getId, categoryFilter, RedisConstant.BloomFilterEnum.CATEGORY.getName());
        loadAndAddIds(artTopicMapper::selectAllWithoutPage, ArtTopic::getId, topicFilter, RedisConstant.BloomFilterEnum.TOPIC.getName());
    }

    private <T> void loadAndAddIds(Supplier<List<T>> dataSupplier,
                                   Function<T, Integer> idExtractor,
                                   RBloomFilter<Integer> filter,
                                   String entityName) {
        List<T> data = dataSupplier.get();
        data.parallelStream()
                .map(idExtractor)
                .forEach(filter::add);
        log.info("{} 布隆过滤器加载完成，数量: {}", entityName, data.size());
    }




    /*@Override
    public void run(String... args) throws Exception {
        // 获取艺术作品布隆过滤器
        RBloomFilter<Integer> artWorkRBloomFilter = redissonClient.getBloomFilter(RedisConstant.ART_WORK_BLOOM_FILTER_KEY);
        // 获取艺术家布隆过滤器
        RBloomFilter<Integer> artArtistRBloomFilter = redissonClient.getBloomFilter(RedisConstant.ART_ARTIST_BLOOM_FILTER_KEY);
        // 获取话题布隆过滤器
        RBloomFilter<Object> artTopicRBloomFilter = redissonClient.getBloomFilter(RedisConstant.ART_TOPIC_BLOOM_FILTER_KEY);
        // 获取类别布隆过滤器
        RBloomFilter<Object> artCategoryRBloomFilter = redissonClient.getBloomFilter(RedisConstant.ART_CATEGORY_BLOOM_FILTER_KEY);
        // 获取流派布隆过滤器
        RBloomFilter<Object> artMovementRBloomFilter = redissonClient.getBloomFilter(RedisConstant.ART_MOVEMENT_BLOOM_FILTER_KEY);

        //初始化布隆过滤器, 参数1: 预计存储元素个数, 参数2: 误判率
        artWorkRBloomFilter.tryInit(RedisConstant.BLOOM_FILTER_EXPECTED_ELEMENTS, RedisConstant.BLOOM_FILTER_ERROR_RATE);
        artArtistRBloomFilter.tryInit(RedisConstant.BLOOM_FILTER_EXPECTED_ELEMENTS, RedisConstant.BLOOM_FILTER_ERROR_RATE);
        artTopicRBloomFilter.tryInit(RedisConstant.BLOOM_FILTER_EXPECTED_ELEMENTS, RedisConstant.BLOOM_FILTER_ERROR_RATE);
        artCategoryRBloomFilter.tryInit(RedisConstant.BLOOM_FILTER_EXPECTED_ELEMENTS, RedisConstant.BLOOM_FILTER_ERROR_RATE);
        artMovementRBloomFilter.tryInit(RedisConstant.BLOOM_FILTER_EXPECTED_ELEMENTS, RedisConstant.BLOOM_FILTER_ERROR_RATE);

        // 从数据库中加载所有艺术作品
        List<ArtWork> artWorks = artWorkMapper.listAll();
        // 从数据库中加载所有艺术家
        List<ArtArtist> artArtists = artArtistMapper.selectAllWithoutPage();
        // 从数据库中加载所有流派
        List<ArtMovement> artMovements = artMovementMapper.getAllWithoutPage();
        // 从数据库中加载所有类别
        List<ArtCategory> artCategories = artCategoryMapper.selectAllWithoutPage();
        // 从数据库中加载所有话题
        List<ArtTopic> artTopics = artTopicMapper.selectAllWithoutPage();

        // 将 艺术作品ID 添加到布隆过滤器中
        for (ArtWork artWork : artWorks) {
            artWorkRBloomFilter.add(artWork.getId());
        }

        // 将 艺术家ID 添加到布隆过滤器中
        for (ArtArtist artArtist : artArtists) {
            artArtistRBloomFilter.add(artArtist.getId());
        }

        // 将 流派ID 添加到布隆过滤器中
        for (ArtMovement artMovement : artMovements) {
            artMovementRBloomFilter.add(artMovement.getId());
        }

        // 将 类别ID 添加到布隆过滤器中
        for (ArtCategory artCategory : artCategories) {
            artCategoryRBloomFilter.add(artCategory.getId());
        }

        // 将 话题ID 添加到布隆过滤器中
        for (ArtTopic artTopic : artTopics) {
            artTopicRBloomFilter.add(artTopic.getId());
        }

        log.info("布隆过滤器初始化完成，已加载 {} 个艺术作品 ID。", artWorks.size());
        log.info("布隆过滤器初始化完成，已加载 {} 个艺术家 ID。", artArtists.size());
        log.info("布隆过滤器初始化完成，已加载 {} 个流派 ID。", artMovements.size());
        log.info("布隆过滤器初始化完成，已加载 {} 个类别 ID。", artCategories.size());
        log.info("布隆过滤器初始化完成，已加载 {} 个话题 ID。", artTopics.size());
    }*/
}